Skip to content

Add callback for token generation to API client#123

Merged
helmut-hoffer-von-ankershoffen merged 1 commit intomainfrom
chore/client-token-refresh-logic
Oct 2, 2025
Merged

Add callback for token generation to API client#123
helmut-hoffer-von-ankershoffen merged 1 commit intomainfrom
chore/client-token-refresh-logic

Conversation

@akunft
Copy link
Copy Markdown
Collaborator

@akunft akunft commented Sep 15, 2025

Currently, the access token used in the API client is obtained once when the client is initialized. This can cause problems when the client is initialized once and then used for multiple calls as there is no new token requested even if it runs out of its lifetime.

This PR introduces a inherited Configuration class for the generated API client that allows to define a callback function that is called every time a new request is made with the client. The callback is then responsible to generate a new token if the old one runs out -- exactly what our get_token function in the _authentication module does.

Given this new setup, a new token is created if necessary no matter if the client is only initialized once and reused or freshly initialized for each call to the API.

@akunft akunft marked this pull request as draft September 15, 2025 22:00
@codecov
Copy link
Copy Markdown

codecov bot commented Sep 15, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@akunft akunft force-pushed the chore/client-token-refresh-logic branch from 0875cf7 to ebceaae Compare September 17, 2025 19:50
@akunft akunft self-assigned this Sep 17, 2025
@akunft akunft force-pushed the chore/client-token-refresh-logic branch from ebceaae to 99f388e Compare September 17, 2025 19:52
@akunft akunft marked this pull request as ready for review September 17, 2025 19:52
@akunft akunft force-pushed the chore/client-token-refresh-logic branch from 99f388e to a97de01 Compare September 18, 2025 16:31
@claude
Copy link
Copy Markdown

claude bot commented Sep 29, 2025

Pull Request Review: Add callback for token generation to API client

Summary

This PR introduces a dynamic token provider mechanism to the API client, addressing a critical issue where long-lived client instances could fail due to expired authentication tokens. The implementation creates a custom configuration class that overrides the static token approach with a callback-based system.

Code Quality Assessment ✅

Architecture & Design - Excellent

  • Clean inheritance pattern: The _OAuth2TokenProviderConfiguration class elegantly extends the generated Configuration class
  • Proper separation of concerns: Token management logic remains in the authentication module while client configuration handles the integration
  • Backwards compatibility: The changes don't break existing API usage patterns
  • Follows SOLID principles: Single responsibility and open/closed principle well maintained

Implementation Quality - Very Good

  • Type hints: Proper use of Callable[[], str] | None and AuthSettings return types
  • Error handling: Graceful fallback when no token provider is provided
  • Naming conventions: Clear, descriptive class and method names following the project's style
  • Documentation: Good docstring explaining the purpose and necessity of the custom configuration

Security Analysis ✅

No Security Concerns Identified

  • Token security: Tokens are still obtained through the existing secure get_token() function
  • No credential exposure: No hardcoded tokens or credentials introduced
  • Callback isolation: The token provider callback is properly encapsulated
  • OAuth2 compliance: Maintains proper Bearer token format and header structure

Performance Considerations ✅

Improved Performance Characteristics

  • Lazy token retrieval: Tokens are only fetched when needed for actual API calls
  • Reduced authentication failures: Eliminates failures due to expired tokens in long-lived clients
  • Minimal overhead: The callback mechanism adds negligible performance cost
  • Cache-friendly: Still leverages the existing token caching mechanism via get_token(use_cache=cache_token)

Test Coverage Analysis ✅

Comprehensive Test Suite - Excellent

The new test file client_token_provider_test.py provides solid coverage:

  1. test_oauth2_token_provider_configuration_uses_token_provider(): Verifies callback execution and token formatting
  2. test_oauth2_token_provider_configuration_no_token(): Tests graceful degradation when no provider is set
  3. test_client_passes_token_provider(): Ensures proper integration between client and configuration
  4. test_client_me_calls_api(): Validates end-to-end functionality

Testing best practices followed:

  • ✅ Proper mocking of external dependencies
  • ✅ Both positive and negative test cases
  • ✅ Integration-level testing
  • ✅ Follows existing project test patterns

Technical Implementation Details

Key Changes Analysis

  1. New Configuration Class (_OAuth2TokenProviderConfiguration):

    def auth_settings(self) -> AuthSettings:
        token = self.token_provider() if self.token_provider else None
        if not token:
            return {}
        return {
            "OAuth2AuthorizationCodeBearer": {
                "type": "oauth2", "in": "header", 
                "key": "Authorization", "value": f"Bearer {token}"
            }
        }
    • Correct: Properly implements the AuthSettings TypedDict structure
    • Secure: Maintains OAuth2 Bearer token standard
    • Robust: Handles None token gracefully
  2. Client Integration:

    def token_provider() -> str:
        return get_token(use_cache=cache_token)
    • Efficient: Reuses existing authentication infrastructure
    • Configurable: Respects the cache_token parameter
    • Clean: Simple closure that encapsulates the authentication logic

Minor Suggestions for Improvement

1. Enhanced Error Handling (Optional)

Consider adding more specific error handling in the token provider:

def token_provider() -> str:
    try:
        return get_token(use_cache=cache_token)
    except Exception as e:
        logger.error("Token provider failed: %s", e)
        raise

2. Type Safety Enhancement (Optional)

The current implementation is solid, but you could make the return type more explicit:

def auth_settings(self) -> AuthSettings:
    if not self.token_provider:
        return {}
    
    token = self.token_provider()
    if not token:
        return {}
    
    return {
        "OAuth2AuthorizationCodeBearer": {
            "type": "oauth2",
            "in": "header", 
            "key": "Authorization",
            "value": f"Bearer {token}",
        }
    }

Potential Considerations

Thread Safety

The implementation should be thread-safe since:

  • get_token() handles its own synchronization
  • No shared mutable state in the configuration class
  • Each API call gets a fresh token through the callback

Performance Under Load

  • Token caching in get_token() prevents excessive authentication requests
  • The 5-minute refresh buffer in the authentication module provides good balance

Final Verdict ✅ APPROVED

This is a well-architected solution that elegantly solves the token expiration problem for long-lived clients. The implementation:

  • Follows project conventions and architectural patterns
  • Maintains security standards without introducing vulnerabilities
  • Provides excellent test coverage with meaningful test cases
  • Improves user experience by preventing authentication failures
  • Is backwards compatible and non-breaking

The code is production-ready and significantly improves the SDK's reliability for long-running applications.


Review conducted following the project's CLAUDE.md guidelines for code quality, security, and testing standards.

@claude
Copy link
Copy Markdown

claude bot commented Oct 2, 2025

Code Review - PR #123: Add callback for token generation to API client

Summary

This PR introduces a callback-based token refresh mechanism to solve a critical issue where long-lived API clients could fail when tokens expire during extended operations. The implementation is solid and well-architected, with good test coverage.


✅ Strengths

  1. Solves a Real Problem: Addresses token expiration for long-lived client instances by generating fresh tokens on-demand rather than once at initialization.

  2. Clean Architecture: The _OAuth2TokenProviderConfiguration class properly extends the generated Configuration class following the inheritance pattern.

  3. Excellent Test Coverage: Three comprehensive test cases covering token provider callback execution, graceful handling of missing token provider, and integration with the Client class.

  4. Backward Compatible: No breaking changes to the public API - existing code continues to work.

  5. Follows Repository Conventions: Private class naming with underscore prefix, type hints throughout, Google-style docstrings, proper import organization.


🔍 Code Quality Observations

Type Hints: Implementation correctly uses Callable, AuthSettings, and optional types.

Security: Token provider is called on every request via auth_settings() method. No token storage in configuration object. Tokens remain ephemeral and fresh.


📝 Minor Suggestions (Non-Blocking)

1. Docstring Enhancement: Consider clarifying that the callback is invoked on EVERY API request to ensure tokens are always fresh, even for long-lived client instances.

2. Thread Safety: Consider documenting thread-safety requirements if clients are used in multi-threaded contexts. The token_provider callable should be thread-safe as auth_settings() may be called concurrently.

3. Test Enhancement: Consider adding a test verifying the token provider is called multiple times for successive API calls to demonstrate the on-demand refresh behavior.

4. Logging: Consider adding debug logging to help trace token refresh behavior for troubleshooting.


🎯 Performance Considerations

The token provider is called on every request. Since get_token() has a 5-minute buffer check with cached tokens, the overhead should be minimal (just timestamp comparison for cached tokens). No action needed for this PR.


🔒 Security Assessment

✅ No security concerns identified. Token provider pattern is secure, no token leakage in logs, follows OAuth2 best practices, and properly integrates with existing authentication flow.


🧪 Testing

The tests are well-structured and cover token provider invocation, null handling, client integration, and API method calls. Recommendation: Run make test to ensure no regressions.


📊 Overall Assessment

Status: ✅ APPROVED - Ready to merge pending CI

Quality Score: 9/10

  • Clean implementation ✅
  • Solves critical bug ✅
  • Good test coverage ✅
  • Follows conventions ✅
  • Minor documentation opportunities ⚡

Great work solving this token refresh issue! The callback pattern is the right solution. 🚀


Review based on repository CLAUDE.md conventions and SDK architecture patterns.

@helmut-hoffer-von-ankershoffen helmut-hoffer-von-ankershoffen merged commit 6494bcc into main Oct 2, 2025
3 of 14 checks passed
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Oct 2, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants